package com.atmilan.quartz.sync.pull.europe.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.atmilan.quartz.utils.product.EuropeProductUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.atmilan.quartz.constant.Constants;
import com.atmilan.quartz.constant.enums.ProductTypeEnum;
import com.atmilan.quartz.constant.enums.SyncStatusEnum;
import com.atmilan.quartz.model.dto.crmeb.StoreProductCrmebRequest;
import com.atmilan.quartz.model.entity.crmeb.StoreProduct;
import com.atmilan.quartz.model.entity.crmeb.StoreProductAttr;
import com.atmilan.quartz.model.entity.crmeb.StoreProductAttrResult;
import com.atmilan.quartz.model.entity.crmeb.StoreProductAttrValue;
import com.atmilan.quartz.model.entity.crmeb.StoreProductDescription;
import com.atmilan.quartz.model.entity.crmeb.SystemConfig;
import com.atmilan.quartz.model.entity.europe.EuropeBrand;
import com.atmilan.quartz.model.entity.europe.EuropeProduct;
import com.atmilan.quartz.model.entity.europe.EuropeProductSku;
import com.atmilan.quartz.model.entity.europe.EuropeProductSkuMerged;
import com.atmilan.quartz.service.IStoreProductAttrResultService;
import com.atmilan.quartz.service.IStoreProductAttrService;
import com.atmilan.quartz.service.IStoreProductAttrValueService;
import com.atmilan.quartz.service.IStoreProductDescriptionService;
import com.atmilan.quartz.service.IStoreProductService;
import com.atmilan.quartz.service.ISystemAttachmentService;
import com.atmilan.quartz.service.ISystemConfigService;
import com.atmilan.quartz.sync.pull.buyer.service.IBuyerBrandService;
import com.atmilan.quartz.sync.pull.europe.service.IEuropeBrandService;
import com.atmilan.quartz.sync.pull.europe.service.IEuropeCategoryService;
import com.atmilan.quartz.sync.pull.europe.service.IEuropeProductService;
import com.atmilan.quartz.sync.pull.europe.service.IEuropeProductSkuMergedService;
import com.atmilan.quartz.sync.pull.europe.service.IEuropeProductSkuService;
import com.atmilan.quartz.sync.pull.europe.service.IEuropeSyncService;
import com.atmilan.quartz.sync.push.crmeb.domain.StoreProductAttrValueRequest;
import com.atmilan.quartz.utils.EuropeUtil;
import com.atmilan.quartz.utils.ImageSearchUtils;
import com.atmilan.quartz.utils.OSSUtil;
import com.atmilan.quartz.utils.source.SourceEuropeProductUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Howe Hsiang
 */
@Slf4j
@Service
public class EuropeSyncServiceImpl implements IEuropeSyncService {
    @Autowired
    EuropeUtil europeUtil;
    @Autowired
    OSSUtil ossUtil;
    @Autowired
    SourceEuropeProductUtil sourceEuropeProductUtil;
    @Autowired
    IEuropeBrandService europeBrandService;
    @Autowired
    IEuropeProductService europeGoodService;
    @Autowired
    IEuropeCategoryService europeCategoryService;
    @Autowired
    IEuropeProductService europeProductService;
    @Autowired
    IEuropeProductSkuService europeProductSkuService;
    @Autowired
    IEuropeProductSkuMergedService europeProductSkuMergedService;
    @Autowired
    ISystemConfigService systemConfigService;
    @Autowired
    IBuyerBrandService buyerBrandService;
    @Autowired
    private ISystemAttachmentService systemAttachmentService;

    @Autowired
    IStoreProductService storeProductService;
    @Autowired
    IStoreProductAttrService storeProductAttrService;
    @Autowired
    IStoreProductAttrValueService storeProductAttrValueService;
    @Autowired
    private IStoreProductAttrResultService storeProductAttrResultService;
    @Autowired
    private IStoreProductDescriptionService storeProductDescriptionService;
    @Autowired
    EuropeProductUtil europeProductUtil;
    
    /**
     * 获取远程Europe数据并保存到数据源
     */
    @Override
    public Boolean syncEuropeProduct() {
        try {
            // 数据清空
            europeProductService.deleteAll();
            europeProductSkuService.deleteAll();
            europeProductSkuMergedService.deleteAll();

            int pageNo = 1;
            int pageSize = 300;
            long millis = System.currentTimeMillis();
            for(;;) {
                List<EuropeProduct> europeProducts = europeProductUtil.selectEuropePage(pageNo, pageSize);
                if(null == europeProducts) {
                    return true;
                }
                
                log.info("--------------- Europe远程抓取数据, 第: {} 页, 总共: {} 条有效数据, 总耗时: {} 分  ---------------", pageNo, europeProducts.size(), (int)((System.currentTimeMillis() - millis) / 1000 / 60));
                if(0 == europeProducts.size()) {
                    pageNo++;
                    continue;
                }
                saveGoods(europeProducts);
                pageNo++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 下发Europe商品
     */
    @Override
    public Boolean pushEuropeProduct() {
        try {
            // 当次更新少于五千条, 则不更新, 并且重新拉取
            int count = europeProductService.count();
            if(1000 > count) {
                systemConfigService.update(Wrappers.<SystemConfig>lambdaUpdate()
                        .eq(SystemConfig :: getName, Constants.EUROPE_SYNC_STATUS)
                        .set(SystemConfig :: getFormId, SyncStatusEnum.PUSH)
                        .set(SystemConfig :: getUpdateTime, new Date())
                        );
                log.info("--------------- Europe商品源数据, 少于规定条数, 不进行下发, 总条数为: {} ---------------", count);
                return false;
            }
            
            // 将所有Europe商品更新状态置为未更新
            storeProductService.update(Wrappers.<StoreProduct>lambdaUpdate()
                    .eq(StoreProduct :: getIsEurope, ProductTypeEnum.EUROPE.getCode())
                    .set(StoreProduct :: getUpdateFlag, false)
                    );
            
            // 商品更新操作
            int pageNo = 1;
            int pageSize = 100;
            int maxPage = (count + pageSize - 1) / pageSize;
            log.info("--------------- 开始分页查询Europe商品源数据, 本次更新总条数为: {} ---------------", count);

            List<EuropeBrand> europeBrands = europeBrandService.list();
            Map<String, EuropeBrand> europeBrandMap = new HashMap<>();
            for(EuropeBrand europeBrand : europeBrands) {
                europeBrandMap.put(europeBrand.getBrandName().toLowerCase(), europeBrand);
            }
            long millis = System.currentTimeMillis();
            while(pageNo <= maxPage) {
                // 分页查询源数据
                PageHelper.startPage(pageNo, pageSize);
                List<EuropeProduct> europeProducts = europeProductService.list();
                PageInfo<EuropeProduct> pageInfo = PageInfo.of(europeProducts);
                List<EuropeProduct> products = pageInfo.getList();
                pushEuropeProduct(products,  europeBrandMap);

                log.info("--------------- Europe下发商品到数据库, 当前页数: {}, 总页数: {}, 耗时: {} 分 ---------------", pageNo, maxPage, (int)((System.currentTimeMillis() - millis) / 1000 / 60));
                pageNo++;
            }
            // 图搜删除
            storeProductService.delSeachImage(ProductTypeEnum.EUROPE);
            // 下架所有未更新数据
            storeProductService.update(Wrappers.<StoreProduct>lambdaUpdate()
                    .eq(StoreProduct :: getIsEurope, ProductTypeEnum.EUROPE.getCode())
                    .eq(StoreProduct::getUpdateFlag, false)
                    .eq(StoreProduct :: getIsShow, true)
                    .eq(StoreProduct :: getIsDel, false)
                    .set(StoreProduct::getIsShow, false)
                    .set(StoreProduct::getStock, 0)
                    .set(StoreProduct::getLastPushTime, new Date())
                    .set(StoreProduct::getIsTusou, false)
                    );
            // 下架所有sku库存
            storeProductService.downloadSku(ProductTypeEnum.EUROPE.getCode());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return false;
    }
    
    private Boolean saveGoods(List<EuropeProduct> europeProducts) {
        for (EuropeProduct europeProduct : europeProducts) {
            try {
                int stock = europeProduct.getStock();
                int goodsId = europeProduct.getGoodId();
                if(0 < stock) {
                    List<EuropeProductSku> skus = europeProduct.getSkuList();
                    List<EuropeProductSkuMerged> skuMergeds = europeProduct.getSkuMergedList();
                    // 源数据保存
                    europeProductService.save(europeProduct);
                    europeProductSkuService.saveBatch(skus);
                    europeProductSkuMergedService.saveBatch(skuMergeds);
                } else {
                    log.info("--------------- europe商品下发, 库存: {}非法, 商品id: {}", stock, goodsId);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }
    
    private void pushEuropeProduct(List<EuropeProduct> europeProduct, Map<String, EuropeBrand> europeBrandMap) {
        try {
            for (EuropeProduct ep : europeProduct) {
                List<EuropeProductSkuMerged> skuMergeds = europeProductSkuMergedService.list(Wrappers.<EuropeProductSkuMerged>lambdaQuery()
                        .eq(EuropeProductSkuMerged::getGoodsId, ep.getGoodId())
                        .gt(EuropeProductSkuMerged::getStock, 0)
                        );
                List<EuropeProductSku> skus = europeProductSkuService.list(Wrappers.<EuropeProductSku>lambdaQuery()
                        .eq(EuropeProductSku::getGoodsId, ep.getGoodId())
                        .isNotNull(EuropeProductSku::getSize)
                        .gt(EuropeProductSku::getQty, 0)
                        );
                if (CollectionUtils.isEmpty(skuMergeds)) {
                    continue;
                }
                // 库存计算
                int stock = 0;
                for (EuropeProductSkuMerged sku : skuMergeds) {
                    stock += sku.getStock();
                }

                // 对象构建
                EuropeProduct crmebProduct = new EuropeProduct();
                BeanUtils.copyProperties(ep, crmebProduct);
                crmebProduct.setSkuList(skus);
                crmebProduct.setSkuMergedList(skuMergeds);
                
                StoreProductCrmebRequest storeProductCrmebRequest = sourceEuropeProductUtil.buildEuropeProduct(crmebProduct,europeBrandMap);
                
                // 数据保存
                StoreProduct storeProduct = storeProductService.getByBarCode(storeProductCrmebRequest.getBarCode(), storeProductCrmebRequest.getSuppliersId(), storeProductCrmebRequest.getKeyword());
                boolean crmebUpdate = true;
                if (null != storeProduct && null != storeProduct.getLastPushTime()) {
                    long time = (System.currentTimeMillis() - storeProduct.getLastPushTime().getTime()) / 1000 / 60;
                    if (60 > time) {
                        log.info("--------------- 该商品: {} 上次crmeb更新时间: {} 小于一小时, 不进行更新 ---------------", storeProductCrmebRequest.getBarCode(), storeProduct.getLastPushTime());
                        crmebUpdate = false;
                        storeProductService.update(Wrappers.<StoreProduct>lambdaUpdate()
                                .eq(StoreProduct :: getId, storeProduct.getId())
                                .set(StoreProduct :: getUpdateFlag, true)
                                );
                    }
                }
                if(crmebUpdate) {
                    saveCrmebProduct(storeProductCrmebRequest, storeProduct, stock);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void saveCrmebProduct(StoreProductCrmebRequest storeProductCrmebRequest, StoreProduct storeProduct, Integer stock) {
        /****** 主表数据保存 *******/
        StoreProduct storeProductUpdate = new StoreProduct();
        BeanUtils.copyProperties(storeProductCrmebRequest, storeProductUpdate);
        storeProductUpdate.setStock(stock);
        storeProductUpdate.setUpdateFlag(true);
        boolean isUpdate = null != storeProduct;
        Integer productId = 0;
        String barCode = storeProductCrmebRequest.getBarCode();

        if(isUpdate) {
            storeProductService.update(Wrappers.<StoreProduct>lambdaUpdate()
                    .eq(StoreProduct::getId, storeProduct.getId())
                    .set(StoreProduct::getPrice, storeProductUpdate.getPrice())
                    .set(null != storeProductUpdate.getPromotePrice(), StoreProduct::getPromotePrice, storeProductUpdate.getPromotePrice())
                    .set(null != storeProductUpdate.getVipPrice(), StoreProduct::getVipPrice, storeProductUpdate.getVipPrice())
                    .set(null != storeProductUpdate.getKeyword(), StoreProduct::getKeyword, storeProductUpdate.getKeyword())
                    .set(null != storeProductUpdate.getOtPrice(), StoreProduct::getOtPrice, storeProductUpdate.getOtPrice())
                    .set(null != storeProductUpdate.getPostage(), StoreProduct::getPostage, storeProductUpdate.getPostage())
                    .set(null != storeProductUpdate.getBrandId(), StoreProduct::getBrandId, storeProductUpdate.getBrandId())
                    .set(null != storeProductUpdate.getBrandName(), StoreProduct::getBrandName, storeProductUpdate.getBrandName())
                    .set(null != storeProductUpdate.getSuppliersId(), StoreProduct::getSuppliersId, storeProductUpdate.getSuppliersId())
                    .set(null != storeProductUpdate.getSuppliersName(), StoreProduct::getSuppliersName, storeProductUpdate.getSuppliersName())
                    .set(null != storeProductUpdate.getCateId(), StoreProduct::getCateId, storeProductUpdate.getCateId())
                    .set(null != storeProductUpdate.getGiveIntegral(), StoreProduct::getGiveIntegral, storeProductUpdate.getGiveIntegral())
                    .set(null != storeProductUpdate.getCost(), StoreProduct::getCost, storeProductUpdate.getCost())
                    .set(null != storeProductUpdate.getSourceCost(), StoreProduct::getSourceCost, storeProductUpdate.getSourceCost())
                    .set(null != storeProductUpdate.getSpecType(), StoreProduct::getSpecType, storeProductUpdate.getSpecType())
                    .set(null != storeProductUpdate.getCreateTime(), StoreProduct::getCreateTime, storeProductUpdate.getCreateTime())
                    .set(null != storeProductUpdate.getLastPushTime(), StoreProduct::getLastPushTime, storeProductUpdate.getLastPushTime())
                    .set(null != storeProductUpdate.getIsEurope(), StoreProduct::getIsEurope, storeProductUpdate.getIsEurope())
                    .set(StoreProduct::getUpdateFlag, storeProductUpdate.getUpdateFlag())
                    .set(StoreProduct::getIsShow, true)
                    .set(StoreProduct::getStock, stock)
                    );
            productId = storeProduct.getId();
            barCode = storeProduct.getBarCode();
        } else {
            storeProductService.save(storeProductUpdate);
            productId = storeProductUpdate.getId();
        }
        /****** attr表保存 ********/
        storeProductAttrService.removeByProductId(productId);
        List<StoreProductAttr> attrs = storeProductCrmebRequest.getAttr();
        for(StoreProductAttr attr : attrs) {
            attr.setProductId(productId);
            attr.setBarCode(barCode);
            attr.setAttrValues(StringUtils.strip(attr.getAttrValues().replace("\"", ""), "[]"));
        }
        storeProductAttrService.saveBatch(attrs);
        /****** value表保存 *********/
//        List<StoreProductAttrValue> dbStoreProductAttrValues = storeProductAttrValueService.list(Wrappers.<StoreProductAttrValue>lambdaQuery().eq(StoreProductAttrValue::getProductId, productId));
//        Map<String, StoreProductAttrValue> dbStoreProductAttrValueMap = dbStoreProductAttrValues.stream().collect(Collectors.toMap(StoreProductAttrValue::getSourceSkuId, s -> s, (value1, value2 )->{return value1;}));
        // 删除所有value
        storeProductAttrValueService.removeByProductId(productId);
        List<StoreProductAttrValueRequest> storeProductAttrValuesRequest = storeProductCrmebRequest.getAttrValue();
        List<StoreProductAttrValue> values = new ArrayList<>();
        for (StoreProductAttrValueRequest attrValuesRequest : storeProductAttrValuesRequest) {
            attrValuesRequest.setProductId(productId);
            attrValuesRequest.setBarCode(barCode);
            StoreProductAttrValue spav = new StoreProductAttrValue();
            BeanUtils.copyProperties(attrValuesRequest, spav);
            List<String> skuList = new ArrayList<>();
            for (Map.Entry<String, String> vo : attrValuesRequest.getAttrValue().entrySet()) {
                skuList.add(vo.getValue());
                spav.setSuk(String.join(",", skuList));
            }
            spav.setAttrValue(JSON.toJSONString(attrValuesRequest.getAttrValue()));
//            StoreProductAttrValue tempValue = dbStoreProductAttrValueMap.get(spav.getSourceSkuId());
//            if (null != tempValue) {
//                spav.setId(tempValue.getId());
//            }
            values.add(spav);
        }
        storeProductAttrValueService.saveBatch(values);
        /****** result表保存 ******/
        storeProductAttrResultService.remove(Wrappers.<StoreProductAttrResult>lambdaQuery().eq(StoreProductAttrResult::getProductId, productId));
        StoreProductAttrResult attrResult = new StoreProductAttrResult(/*0,*/ productId, systemAttachmentService.clearPrefix(JSON.toJSONString(storeProductCrmebRequest.getAttrValue())), Integer.parseInt(String.valueOf(System.currentTimeMillis() / 1000L)), Constants.PRODUCT_TYPE_NORMAL, barCode);
        storeProductAttrResultService.save(attrResult);

        // 处理富文本
        StoreProductDescription dbDescription = storeProductDescriptionService.getOne(Wrappers.<StoreProductDescription>lambdaQuery()
        		.eq(StoreProductDescription :: getProductId, storeProductUpdate.getId())
        		.last("LIMIT 1")
        		);
        StoreProductDescription storeProductDescription = StoreProductDescription.getDescriptionByProduct(storeProductUpdate);
        storeProductDescription.setId(ObjectUtil.isNotNull(dbDescription) ? dbDescription.getId() : null);
        storeProductDescription.setProductId(storeProductUpdate.getId());
        storeProductDescriptionService.saveOrUpdate(storeProductDescription);
    }
    
}
